/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package data;

/**
 * @author lailiaidi
 * This class is to process input from HTML client and create input to SMTP client
 */
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import model.MailBody;
import model.MailEnvelope;
import model.MailMIMEHeader;
import smtp.MIMEutility;
import smtp.SMTPClient;
import smtp.SMTPLookup;

public class DataHandler {

    private Timer timer;
    private final String obStrNoReplySender = "noreply@mail.ik2213.lab";
    private SMTPLookup obSMTPSenderLookup, obSMTPRecipientLookup;
    private DataQueue obDataQueue;
    private boolean isNeedConfirmation;//Flag that mark the email need confirmation back to the sender
    private boolean isFutureDeliverMail;//Flag that mark the confirmation email
    private boolean isValidSender;//Flag sender's email address validation
    private boolean isValidReceiver;//Flag recipient's email address validation

    /* This is constructore to send regular email */
    public DataHandler(String emailData, DataQueue obDataQueue) {
        this.obDataQueue = obDataQueue;
        this.isValidSender = this.isValidReceiver = true;
        this.isNeedConfirmation = this.isFutureDeliverMail = false;

        String obStrFrom = getFrom(emailData);
        String obStrTo = getTo(emailData);
        String obStrSubject = getSubject(emailData);
        String obStrDelay = getDelay(emailData);
        String obStrSMTPServerName = getSMTP(emailData);
        String obStrSMTPServerAddress = obStrSMTPServerName;
        String obStrBody = MIMEutility.MIMEEncoder(getBody(emailData));
        //Check the Input FROM text field If the sender's email is valid or not
        obSMTPSenderLookup = new SMTPLookup(obStrFrom);
        if (obStrFrom.length() < 0 || !obSMTPSenderLookup.isValidEmail()) {
            isValidSender = false;
        } else {
            //Check the Input TO text field If the sender's email is valid or not
            obSMTPRecipientLookup = new SMTPLookup(obStrTo);
            if (obStrTo.length() < 0 || !obSMTPRecipientLookup.isValidEmail()) {
                isValidReceiver = false;
            } else {
                if (obStrSMTPServerName.length() == 0 && obStrTo.length() > 0) {
                    /* If the "SMTP Server" field is empty, WebMail  examine the receiver's e-mail address
                    and request DNS lookup to obtain the mail server for that domain (an "MX" record) */
                    obStrSMTPServerName = obSMTPRecipientLookup.getSMTPServerHostName();
                }
                //We might not find any smtp server address, because  after we do MX lookup we might find the domain in recipient's mail address might not valid,
                if (obStrSMTPServerName != null && obStrSMTPServerName.length() > 0) {
                    obStrSMTPServerAddress = obStrSMTPServerName;
                    //If SMTP is given as a host name, it needs to be translated to an IP address.
                    String tempAddress = obSMTPRecipientLookup.getSMTPServerAddress(obStrSMTPServerName);
                    //If finding the IP address is fail, just use the SMTP server host name
                    if (tempAddress != null && tempAddress.length() > 0) {
                        obStrSMTPServerAddress = tempAddress;
                    }
                } else {
                    //There is no SMTP server host name can be found
                    isValidReceiver = false;
                }
            }
        }

        //After everything is ok, call SMTPClient to make connection with SMTPServer
        if (isValidSender && isValidReceiver) {
            // Now after get all the data, we make SMTP Data Object
            String obStrType = "text/plain;charset=ISO-8859-15";
            String obStrTypeVersion = "1.0";
            String obStrEncoding = "quoted-printable";
            MailMIMEHeader obMailMIME = getMailMIME(obStrType, obStrTypeVersion, obStrEncoding);

            int obIntDelay = 0;
            try{
                obIntDelay = Integer.parseInt(obStrDelay);
            }catch(Exception ex){
            }
            
            if (obIntDelay > 0) {
                MailBody obMailBody = getMailBody(obStrFrom, obStrFrom, obStrTo, obStrSubject, obStrBody, obIntDelay);
                MailEnvelope obMailEnvelope = getMailEnvelope(obStrFrom, obStrTo, obMailBody, obMailMIME);

                // Means the delivery status of this email must be confirmed back to the sender's email address
                this.isNeedConfirmation = true;
                DateFormat dFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                Date dDate = new Date();
                obDataQueue.addMailQueueData(obMailEnvelope.getSender(), obMailEnvelope.getRecipient(), obMailEnvelope.getMailData().getSubject(),
                        dFormat.format(dDate), obMailEnvelope.getMailData().getDate(), null, 0, "On Delay Process");
                RemindTask obRemindTask = new RemindTask(obMailEnvelope, obStrSMTPServerName, obStrSMTPServerAddress);
                timer = new Timer();
                timer.schedule(obRemindTask, obIntDelay * 1000);
            } else {
                MailBody obMailBody = getMailBody(obStrFrom, obStrFrom, obStrTo, obStrSubject, obStrBody, 0);
                MailEnvelope obMailEnvelope = getMailEnvelope(obStrFrom, obStrTo, obMailBody, obMailMIME);
                startSMTPClient(obMailEnvelope, obStrSMTPServerName, obStrSMTPServerAddress);
            }
        }
    }

    /* This is constructore to send confirmation email to the sender for future delivery*/
    public DataHandler(String obStrSender, String obStrRecipient, int statusDelivery) {
        this.obDataQueue = null;
        this.isValidSender = this.isValidReceiver = true;
        //Means this email don't need confirmation to the sender, because this is confirmation email itself
        this.isNeedConfirmation = false;
        this.isFutureDeliverMail = true;
        String obStrSubject = "Mail Delivery Status";
        String obStrBody = "";
        switch (statusDelivery) {
            case 1:
                obStrBody = obStrSender + "'s mail to " + obStrRecipient + " is successfully delivered";
                break;
            case 2:
                obStrBody = obStrSender + "'s mail to " + obStrRecipient + " is failed to be delivered";
                break;
        }
        String obStrSMTPServerName = "";
        String obStrSMTPServerAddress = "";
        //TEMP obStrSMTPServerName = "localhost";
        //Check the Input TO text field If the sender's email is valid or not
        obSMTPRecipientLookup = new SMTPLookup(obStrSender);
        if (obStrRecipient.length() > 0) {
            /* If the "SMTP Server" field is empty, WebMail  examine the receiver's e-mail address
            and request DNS lookup to obtain the mail server for that domain (an "MX" record) */
            obStrSMTPServerName = obSMTPRecipientLookup.getSMTPServerHostName();
        }

        //We might not find any smtp server address, because  after we do MX lookup we might find the domain in recipient's mail address might not valid,
        if (obStrSMTPServerName != null && obStrSMTPServerName.length() > 0) {
            obStrSMTPServerAddress = obStrSMTPServerName;
            /* If SMTP is given as a host name, it needs to be translated to an IP address. */
            String tempAddress = obSMTPRecipientLookup.getSMTPServerAddress(obStrSMTPServerName);
            //If we fail on finding the IP address, just use the SMTP server host name
            if (tempAddress != null && tempAddress.length() > 0) {
                obStrSMTPServerAddress = tempAddress;
            }
        } else {
            //There is no SMTP server host name can be found
            isValidReceiver = false;
        }

        //After everything is ok, call SMTPClient to make connection with SMTPServer
        if (isValidSender && isValidReceiver) {
            //Now after get all the data, we make SMTP Data Object
            System.out.println("===Sending Confimation Mail===");
            MailBody obMailBody = getMailBody(obStrNoReplySender, obStrNoReplySender, obStrSender, obStrSubject, obStrBody, 0);
            MailEnvelope obMailEnvelope = getMailEnvelope(obStrNoReplySender, obStrSender, obMailBody, null);
            startSMTPClient(obMailEnvelope, obStrSMTPServerName, obStrSMTPServerAddress);
        }
    }

    public boolean getSMTPValidation() {
        if (!isValidReceiver || !isValidSender) {
            return false;
        } else {
            return true;
        }
    }

    /* Method to implement Future Delivery Feature */
    class RemindTask extends TimerTask {

        MailEnvelope obMailEnvelope;
        String obStrSMTPServerName, obStrSMTPServerAddress;

        public RemindTask(MailEnvelope obMailEnvelope, String obStrSMTPServerName, String obStrSMTPServerAddress) {
            this.obMailEnvelope = obMailEnvelope;
            this.obStrSMTPServerName = obStrSMTPServerName;
            this.obStrSMTPServerAddress = obStrSMTPServerAddress;
        }

        public void run() {
            System.out.println("Message is sent now");
            startSMTPClient(obMailEnvelope, obStrSMTPServerName, obStrSMTPServerAddress);
            timer.cancel(); //Terminate the timer thread
        }
    }

    /* Method to call SMTPClient to make connection with SMTPServer, we only call this after sure all the data is valid */
    private void startSMTPClient(MailEnvelope obMailEnvelope, String obStrSMTPServerName, String obStrSMTPServerAddress) {
        try {
            if (isNeedConfirmation) {
                obDataQueue.updateMailQueueData(obMailEnvelope.getMailData().getDate(), null, 0, "Yeps, Your email is sent now.");
            } else if (!isFutureDeliverMail) {
                obDataQueue.addMailQueueData(obMailEnvelope.getSender(), obMailEnvelope.getRecipient(), obMailEnvelope.getMailData().getSubject(),
                        obMailEnvelope.getMailData().getDate(), null, 0, "Yeps, Your email is sent now.");
            }
            SMTPClient clientUsingSockets = new SMTPClient(obStrSMTPServerAddress, obStrSMTPServerName, obMailEnvelope, isNeedConfirmation, isFutureDeliverMail, obDataQueue);
            clientUsingSockets.start();
        } catch (Exception e) {
        }
    }

    //This method is used to decode the data from the web interface
    public static String getFrom(String data) {
        int x = data.indexOf("textfieldFrom");//data.indexOf('=');
        int y = data.indexOf("&textfieldTo");//data.indexOf('&');
        return data.substring(x + 14, y);
    }

    public String getTo(String data) {
        int x = data.indexOf("textfieldTo");
        int y = data.indexOf("&textfieldSubject");
        return data.substring(x + 12, y);
    }

    public String getSubject(String data) {
        int x = data.indexOf("textfieldSubject");
        int y = data.indexOf("&textfieldSMTP");
        return data.substring(x + 17, y);
    }

    public String getSMTP(String data) {
        int x = data.indexOf("textfieldSMTP");
        int y = data.indexOf("&textfieldDelay");
        return data.substring(x + 14, y);
    }

    public String getDelay(String data) {
        int x = data.indexOf("textfieldDelay");
        int y = data.indexOf("&textareaMessage");
        return data.substring(x + 15, y);
    }

    public String getBody(String data) {
        int x = data.indexOf("textareaMessage");
        int y = data.indexOf("&btnSubmit");
        return data.substring(x + 16, y);
    }

    private MailBody getMailBody(String obStrFrom, String obStrReplyTo, String obStrTo, String obStrSubject, String obStrBody, int obIntDelay) {
        MailBody obMailBody = new MailBody();
        obMailBody.setFrom(obStrFrom);
        obMailBody.setReplyTo(obStrReplyTo);
        obMailBody.setTo(obStrTo);
        obMailBody.setSubject(obStrSubject);

        DateFormat dFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Date dDate = new Date();
        if (obIntDelay > 0) {
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.SECOND, obIntDelay);
            obMailBody.setDate(dFormat.format(cal.getTime()));
        } else {
            obMailBody.setDate(dFormat.format(dDate));
        }
        obMailBody.setBody(obStrBody);
        return obMailBody;
    }

    private MailMIMEHeader getMailMIME(String obStrContentType, String obStrMIMEVersion, String obStrEncoding) {
        MailMIMEHeader obMailMIME = new MailMIMEHeader();
        obMailMIME.setContentType(obStrContentType);
        obMailMIME.setMIMEVersion(obStrMIMEVersion);
        obMailMIME.setEncoding(obStrEncoding);
        return obMailMIME;
    }

    private MailEnvelope getMailEnvelope(String obSender, String obRecipient, MailBody obMailData, MailMIMEHeader obMailMIME) {
        MailEnvelope obMailEnvelope = new MailEnvelope();
        obMailEnvelope.setSender(obSender);
        obMailEnvelope.setRecipient(obRecipient);
        obMailEnvelope.setMailData(obMailData);
        obMailEnvelope.setMailMIME(obMailMIME);
        return obMailEnvelope;
    }
}
